package com.hdu.dwh.controller;

import java.sql.SQLException;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.hdu.dwh.dtos.ModelDto;
import com.hdu.dwh.dtos.model_dtos.BuildModelDto;
import com.hdu.dwh.dtos.model_dtos.ModelCreateDto;
import com.hdu.dwh.dtos.model_dtos.PreviewModelDto;
import com.hdu.dwh.dtos.model_dtos.PreviewTableDto;
import com.hdu.dwh.pojos.FlinkJob;
import com.hdu.dwh.pojos.Model;
import com.hdu.dwh.pojos.QueryResult;
import com.hdu.dwh.pojos.model_pojos.MetaTable;
import com.hdu.dwh.pojos.source_access_pojos.DataWarehouseTable;
import com.hdu.dwh.results.ResponseResult;
import com.hdu.dwh.service.DataWarehouseTableService;
import com.hdu.dwh.service.ModelService;
import com.hdu.dwh.validators.ModelCreateDtoValidator;
import com.hdu.dwh.vos.ModelVo;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping("/model")
@RequiredArgsConstructor
@Tag(name = "模型")
public class ModelController {
    @Autowired
    private final ModelService modelService;

    @Autowired
    private ModelCreateDtoValidator modelCreateDtoValidator;

    @Autowired
    private DataWarehouseTableService dataWarehouseTableService;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        if (binder.getTarget() instanceof ModelCreateDto) {
            binder.addValidators(this.modelCreateDtoValidator);
        }
    }

    @PostMapping("/addModel")
    @Operation(summary = "添加模型", deprecated = true)
    public ResponseResult<?> addModel(@RequestBody ModelDto modelDto) {
        // TODO: modelDto参数校验

        // modelDto转为model对象
        Model model = new Model();
        BeanUtils.copyProperties(modelDto, model);

        // 报存model对象
        this.modelService.save(model);
        return ResponseResult.success("模型添加成功", model);

    }

    @GetMapping("/page")
    @Operation(summary = "分页查询模型")
    public ResponseResult<?> pageModel(Integer current, Integer size) {
        // Page<Model> modelPage = new Page<>(current, size);
        return ResponseResult.success("模型分页查询成功", this.modelService.queryModelVoPage(current, size));
    }

    @PutMapping("/updateModel/{id}")
    @Operation(summary = "更新模型")
    @Parameters({
            @Parameter(name = "id", description = "模型ID")
    })
    public ResponseResult<?> updateModel(@PathVariable Long id, @RequestBody ModelDto modelDto) {
        // TODO: modelDto参数校验

        // modelDto转为model对象

        Model model = new Model();
        BeanUtils.copyProperties(modelDto, model);
        model.setId(id);
        // TODO: bug 更新模型时模型更新时间被设为null
        return this.modelService.updateById(model)
                ? ResponseResult.success("模型更新成功", model)
                : ResponseResult.fail("模型更新失败");
    }

    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除模型")
    @Parameters({
            @Parameter(name = "id", description = "模型ID")
    })
    public ResponseResult<?> deleteModel(@PathVariable Integer id) throws Exception {
        this.modelService.deleteModel(id);
        return ResponseResult.success("模型删除成功");
    }

    @GetMapping("/list")
    @Operation(summary = "查询所有模型")
    public ResponseResult<?> listModel() {
        return ResponseResult.success("模型查询成功", this.modelService.queryModelVoList());
    }

    @PostMapping("/setFactTable")
    public ResponseResult<?> setFactTable(@RequestParam Integer modelId, @RequestParam Integer sourceTableId) {
        // 1.如果model的factTableId为null，则设置为传入的fact
        // 2.如果model的factTableId不为null，则判断传入的fact是否与model的factTableId相同

        Model model = this.modelService.getById(modelId);
        if (model == null) {
            return ResponseResult.fail("模型不存在");
        }

        return ResponseResult.success();

    }

    @Operation(summary = "根据ID获取模型")
    @Parameters({
            @Parameter(name = "id", description = "模型ID")
    })
    @GetMapping("getModelById")
    public ResponseResult<?> getModelById(@RequestParam Integer id) {
        ModelVo modelVo = this.modelService.queryModelVoById(id);
        return ResponseResult.success("success", modelVo);

    }

    @Operation(summary = "添加模型")
    @PostMapping("createModel")
    public ResponseResult<ModelVo> createModel(@RequestBody @Validated ModelCreateDto modelCreateDto) throws Exception {
        // TODO: modelCreateDto参数校验,禁止同一个数据库下重名
        return ResponseResult.success("模型创建成功", this.modelService.createModel(modelCreateDto));
    }

    @Operation(summary = "构建模型")
    @PostMapping("buildModel")
    public ResponseResult<?> buildModel(@RequestBody @Valid BuildModelDto buildCubeDto) throws Exception {
        FlinkJob createCubeSql = this.modelService.buildModel(buildCubeDto);
        return ResponseResult.success("构建CUBE成功", createCubeSql);
    }

    @Operation(summary = "创建维表")
    @PostMapping("createDimensionTable")
    public ResponseResult<FlinkJob> createDimsionTable(@RequestBody CreateDimDto createDimDto) throws SQLException {
        DataWarehouseTable sourceTable = this.dataWarehouseTableService.getById(createDimDto.getTableId());
        FlinkJob createDimensionTableJob = this.modelService.createDimensionTable(sourceTable, createDimDto.getColumns(), createDimDto.getDimTableName(),  createDimDto.getDescription(), createDimDto.getDatabaseId());
        return ResponseResult.success("维表创建成功", createDimensionTableJob);
    }
    
    @Operation(summary = "模型预览")
    @PostMapping("previewModel")
    public ResponseResult<QueryResult> previewModel(@RequestBody PreviewModelDto modelCreateDto) throws Exception {
        return ResponseResult.success("模型预览成功", this.modelService.previewModel(modelCreateDto));
    }

    @Operation(summary = "维表预览")
    @PostMapping("previewDimTable")
    public ResponseResult<QueryResult> previewDimTable(@RequestBody MetaTable previewDimDto) throws Exception {
        return ResponseResult.success("维表预览成功", this.modelService.previewDimTable(previewDimDto));
    }
}
